using Moq;
using NUnit.Framework;
using Tycho.Grammar;
using Tycho.Parser.Peg;

namespace Tycho.UnitTests.Grammar {
    [TestFixture]
    public class TermMacroCompilerSpecification {
        [Test]
        public void ShouldUseNonTerminalCompilerToCompileNonTerminalProduction () {
            var nonTerminalRuleCompiler = new Mock<INonTerminalRuleCompiler> ();
            var termMacroBuilderCompiler = new Mock<ITermMacroBuilderCompiler> ();

            var nonTerminalProduction = new NonTerminal ();
            var nonTerminalBuilder = new Mock<INonTerminalBuilder> ();
            var compiler = new TermMacroCompiler(nonTerminalRuleCompiler.Object, termMacroBuilderCompiler.Object, () => nonTerminalProduction, nonTerminalBuilder.Object);

            var term = new CompositeTerm ("term-macro", null);

            ITerm ruleTerm = new Mock<ITerm> ().Object;
            term.Add ("rule", ruleTerm, false);

            ITerm termTerm = new Mock<ITerm> ().Object;
            term.Add ("term", termTerm, false);

            var rule = new Mock<IRule> ().Object;
            var multipleCaptures = new string [0];
            var ruleCaptures = new RuleCaptures {Rule = rule, MultipleCaptures = multipleCaptures};
            nonTerminalRuleCompiler.Setup (c => c.Compile (ruleTerm, It.IsAny<ProductionCompilerContext> ()))
                .Returns(ruleCaptures);

            var deferredCompilations = new DeferredCompilations ();
            var precedence = new ChoicePrecedence (null, 32);
            IProduction actualProduction = compiler.Compile (term, precedence, new ProductionCompilerContext (null, null, null, deferredCompilations)).Production;
            deferredCompilations.RunCompilationSteps ();

            Assert.That (actualProduction, Is.SameAs(nonTerminalProduction));
            termMacroBuilderCompiler.Verify (c => c.Compile (termTerm));

            nonTerminalBuilder.Verify (c => c.Build (null, nonTerminalProduction, ruleCaptures));
        }
    }
}